home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Nebula 2
/
Nebula Two.iso
/
Apps
/
ScreenSavers
/
BackSpaceViews
/
DigitalClockView.BackModule
/
DigitalClockView.m
< prev
next >
Wrap
Text File
|
1995-06-12
|
11KB
|
390 lines
//
// DigitalClockView.m
// rev 1.3
// Now supports BackSpace inspector panels
//
// Matt Pharr- pharr@cs.yale.edu
// NeXTMail welcome
//
#import "DigitalClockView.h"
#import <appkit/appkit.h>
#import <defaults/defaults.h>
#import <dpsclient/wraps.h>
#import <libc.h>
#import <stdlib.h>
#import <strings.h>
#import <time.h>
#define AM_PM 0
#define MILITARY 1
@implementation DigitalClockView
/* Fixes the NXImage so that if there isn't room to display it on the
* screen (i.e. it's too big, or the screen/window space is too small)
* it still behaves generally nicely.
*/
- fixPosition
{
/* If we're doing AM/PM time and a leading 0 was taken off the time
* string that strftime returned, let some of the NXImage go off the
* edge of the screen before we force it back on. When the leading 0
* is taken off, we have extra room in currentImage, which is a black
* area at the right side, so we can let that part go off the screen...
*/
if (militaryTime == NO && didShorten == YES) {
if (currentLocation.x + .9 * currentSize.width >= bounds.size.width)
currentLocation.x = bounds.size.width - .9 * currentSize.width;
}
else {
if (currentLocation.x + currentSize.width >= bounds.size.width)
currentLocation.x = bounds.size.width - currentSize.width;
}
if (currentLocation.x <= bounds.origin.x)
currentLocation.x = 0;
if (currentLocation.y + currentSize.height >= bounds.size.height)
currentLocation.y = bounds.size.height - currentSize.height;
if (currentLocation.y <= bounds.origin.y)
currentLocation.y = 0;
return self;
}
/* This handles bouncing the image- i.e. changing the move vector if needed
* when currentImage hits the edge of the screen/window. Note a similar kludge
* as in fixPosition that allows for the truncated AM/PM times.
*/
- bounceIfNeeded
{
if (currentLocation.x <= bounds.origin.x)
moveVector.x= bounceMultiplier * randBetween(0.5, 1.5);
if (militaryTime == NO && didShorten == YES) {
if (currentLocation.x + .9 * currentSize.width >= bounds.size.width)
moveVector.x= bounceMultiplier * (-1) * randBetween(0.5, 1.5);
}
else {
if (currentLocation.x + currentSize.width >= bounds.size.width)
moveVector.x= bounceMultiplier * (-1) * randBetween(0.5, 1.5);
}
if (currentLocation.y <= bounds.origin.y)
moveVector.y= bounceMultiplier * randBetween(0.5, 1.5);
if (currentLocation.y + currentSize.height >= bounds.size.height)
moveVector.y= bounceMultiplier * (-1) * randBetween(0.5, 1.5);
return self;
}
- chooseColor
{
float dr, dg, db;
if ([Window defaultDepthLimit] == NX_TwoBitGrayDepth) {
PSsetgray(1.0); /* yipee! */
}
else {
dr= randBetween(-.1, .1); /* randomly move the red, green, and blue */
dg= randBetween(-.1, .1); /* components of the color around between */
db= randBetween(-.1, .1); /* 0 and 1. There is a minor bummer in that
* you only see the effect of the color
* change once a second, because it only
* draws the time into the bitmap when the
* time changes. Would be an easy modification
* to get it to redraw the bitmap more
* frequently, but its probably not worth
* the processor cycles. Depending on how this
* ends up looking in color (wish I knew!), it
* might be better to replace everything
* between the else and the PSsetrgbcolor
* with just a PSsetrgbcolor(), with constant
* arguments...
*/
currR += dr; currG += dg; currB += db;
if (currR < 0.0) currR= 0.0;
if (currR > 1.0) currR= 1.0;
if (currG < 0.0) currG= 0.0;
if (currG > 1.0) currG= 1.0;
if (currB < 0.0) currB= 0.0;
if (currB > 1.0) currB= 1.0;
PSsetrgbcolor(currR, currG, currB);
}
return self;
}
- oneStep
{
time_t tTime;
struct tm *currentTime;
/* if a new currentImage has been allocated, most likely the size of the
* clock or whether military time is being used or not has changed. Thus,
* it's a good idea to clear out the drawing area, so that no little
* remnants are left hanging around.
*/
if (isNew == YES) {
PSsetgray(0.0);
NXRectFill(&bounds);
isNew= NO;
}
currentLocation.x += moveVector.x;
currentLocation.y += moveVector.y;
[self bounceIfNeeded];
[self fixPosition];
time(&tTime);
currentTime= localtime(&tTime);
if (militaryTime == YES)
strftime(theTime, 14, "%H:%M:%S", currentTime);
else {
strftime(theTime, 14, "%I:%M:%S %p", currentTime);
if (theTime[0] == '0') {
strcpy(theTime, theTime+1); /* take off the leading 0 */
didShorten= YES;
}
else
didShorten= NO;
}
if (strcmp(theTime, lastTime) != 0) { /* if the time has changed... */
strcpy(lastTime, theTime);
currentLocation.x += moveVector.x; /* move it one more time so it's not so jerky */
currentLocation.y += moveVector.y; /* when the time changes... */
[self bounceIfNeeded];
[self fixPosition];
if ([currentImage lockFocus] == YES) { /* draw a new bitmap */
PSsetgray(0.0);
PSrectfill(0, 0, currentSize.width, currentSize.height);
[theFont set];
PSsetgray(.333); /* give it a little shadow */
PSmoveto(14, clockSize);
PSshow(theTime);
PSmoveto(10, clockSize + 2);
[self chooseColor];
PSshow(theTime);
[currentImage unlockFocus];
}
}
[currentImage composite:NX_COPY toPoint:¤tLocation];
usleep((1*1000000)/68);
return self;
}
- (const char *)windowTitle
{
return "Digital Clock";
}
- drawSelf:(const NXRect *)rects :(int)rectCount
{
if (!rects || !rectCount) {
return self;
}
PSsetgray(0);
NXRectFill(rects);
return self;
}
- newClock
{
*theTime= '\0';
*lastTime= '\0';
theFont= [Font newFont:"Times-Roman" size:clockSize];
currR= currG= currB= .5;
if (militaryTime == YES) {
currentSize.width= [theFont getWidthOf:"88:88:88"] + 20;
}
else {
currentSize.width= [theFont getWidthOf:"88:88:88 MM"] + 20;
}
currentSize.height= clockSize + 20;
[currentImage free];
currentImage= [[NXImage alloc] initSize:¤tSize];
[currentImage setFlipped:YES];
isNew= YES; /* make sure oneStep knows it has a new
* bitmap to work with, and will clear
* the screen as needed...
*/
return self;
}
- inspector:sender
{
char buf[MAXPATHLEN];
if (!sharedInspectorPanel) {
sprintf(buf,"%s/%s",[(BSThinker()) moduleDirectory:"DigitalClock"],
"DigitalClock.nib");
[NXApp loadNibFile:buf owner:self withNames:NO];
}
return sharedInspectorPanel;
}
- initFrame:(const NXRect *)frameRect
{
[super initFrame:frameRect];
currentLocation.x= 400.0;
currentLocation.y= 400.0;
moveVector.x= randBetween(0.5, 1.5);
moveVector.y= randBetween(0.5, 1.5);
didShorten= NO;
[self inspector:self]; /* Must do this ourselves here instead of
* letting BackSpace take care of it because
* we use the connections defined in there
* down below where we sent setFloatValue, etc
* to the sliders and other controls.
*/
if (NXGetDefaultValue([NXApp appName], "digClkViewClockSize") == NULL) {
NXWriteDefault([NXApp appName], "digClkViewClockSize", "120.0");
NXWriteDefault([NXApp appName], "digClkViewBounceMult", "1.0");
NXWriteDefault([NXApp appName], "digClkViewMilitary", "NO");
clockSize= 120.0;
bounceMultiplier= 1.0;
militaryTime= NO;
}
else {
clockSize= atof(NXGetDefaultValue([NXApp appName],
"digClkViewClockSize"));
if (clockSize < 10.0 || clockSize > 300.0)
clockSize= 120.0;
bounceMultiplier= atof(NXGetDefaultValue([NXApp appName],
"digClkViewBounceMult"));
if (bounceMultiplier < .1 || bounceMultiplier > 10.0)
bounceMultiplier= 1.0;
if (strcmp(NXGetDefaultValue([NXApp appName], "digClkViewMilitary"),
"YES") == 0) {
militaryTime= YES;
}
else militaryTime= NO;
}
[sizeSlider setFloatValue:clockSize];
[sizeSlider update];
[speedSlider setFloatValue:bounceMultiplier];
[speedSlider update];
if (militaryTime == YES)
[militarySwitch setState:MILITARY];
else
[militarySwitch setState:AM_PM];
[militarySwitch update];
[self newClock];
return self;
}
- setClockSize:sender
{
char temp[40];
clockSize= [sender floatValue];
sprintf(temp, "%f", clockSize);
NXWriteDefault([NXApp appName], "digClkViewClockSize", temp);
[self newClock];
return self;
}
- setBounceMultiplier:sender
{
char temp[40];
bounceMultiplier= [sender floatValue];
sprintf(temp, "%f", bounceMultiplier);
NXWriteDefault([NXApp appName], "digClkViewBounceMult", temp);
/* update the moveVector as needed so that the changes aare reflected
* immediately, instead of forcing the user to wait until the clock
* bounces off of an edge to see the effect..
*/
if (moveVector.x > 0)
moveVector.x= bounceMultiplier * randBetween(0.5, 1.5);
else
moveVector.x= (-1) * bounceMultiplier * randBetween(0.5, 1.5);
if (moveVector.y > 0)
moveVector.y= bounceMultiplier * randBetween(0.5, 1.5);
else
moveVector.y= (-1) * bounceMultiplier * randBetween(0.5, 1.5);
return self;
}
- setMilitaryTime:sender
{
if ([sender state] == MILITARY) {
militaryTime= YES;
NXWriteDefault([NXApp appName], "digClkViewMilitary", "YES");
}
else {
militaryTime= NO;
NXWriteDefault([NXApp appName], "digClkViewMilitary", "NO");
}
[self newClock];
return self;
}
@end